local config     = require "config"
local cjson      = require "cjson.safe"
local httpclient = require "shared.http.client"
local mapper     = require "shared.object.mapper"
local util       = require "proxy.game.common.util"

local ngx        = _G.ngx
local get_response_spec     = util.get_response_spec
local fill_response_header  = util.fill_response_header
local is_match_content_type = util.is_match_content_type
local get_content_decoder   = util.get_content_decoder
local get_method            = util.get_method

local SERVICE = ngx.var.service
local ADDRESS = config.ENV[ngx.var.service]
local ACTION  = ngx.var.action

if not ADDRESS or not ACTION then
  ngx.status = ngx.HTTP_NOT_FOUND
  ngx.exit(ngx.OK)
end

do
  local location = ngx.unescape_uri(ADDRESS..ACTION)
  local method   = get_method(ngx.req)
  local headers  = ngx.req.get_headers()
  ngx.req.read_body()
  local data   = ngx.req.get_body_data()
  local query  = ngx.var.args

  do
    -- add X-Forwarded-For header
    headers['X-Forwarded-For'] = ngx.var.proxy_add_x_forwarded_for
  end

  -- perform http request
  local resp, err = httpclient.new()
    :uri(location)
    :headers(headers)
    :query(query)
    :body(data)
    :send(method, 2000, nil)

  if err or (not resp) then
    ngx.status = 500
    ngx.say(err)
    ngx.exit(ngx.OK)
  end


  -- response
  ngx.header['Server'] = ngx.var.SERVICE_NAME
  ngx.header['Content-Type'] = resp.headers['Content-Type']

  -- has body? has headers? is status 200 OK? is application/json?
  if   not resp.body
    or not resp.headers
    or resp.status ~= 200
    or not is_match_content_type(resp, 'application/json')  then

    ngx.status = resp.status
    -- fill header except 'Server'
    fill_response_header(resp.headers)
    ngx.say(resp.body)
    ngx.exit(ngx.OK)
  end

  do
    local body
    -- according 'Content-Encoding' to decode response body
    local contentDecoder = get_content_decoder(resp)
    if contentDecoder then
      body = contentDecoder.decode(resp.body)
    else
      ngx.header['X-Gateway-Message'] = 'UNKNOWN_ENCODING'
    end

    -- has response specification?
    local resp_spec = get_response_spec(SERVICE, ACTION, method)

    -- can decode response body? has response specification?
    if (not body)  or  (body == cjson.null)  or  (not resp_spec) then
      ngx.status = resp.status
      -- fill header except 'Server'
      fill_response_header(resp.headers)
      ngx.say(resp.body)
      ngx.exit(ngx.OK)
    end

    -- reponse success content
    local reply = mapper.map(body, resp_spec)
    ngx.status = resp.status
    ngx.say(cjson.encode(reply))
    ngx.exit(ngx.OK)
  end
end